package com.wlc.interceptor;

import com.wlc.utils.JwtUtils;
import com.wlc.utils.TokenBlacklist;
import io.jsonwebtoken.Claims;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

@Slf4j
@Component
public class TokenInceptor implements HandlerInterceptor {

    @Autowired
    private TokenBlacklist tokenBlacklist;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //1.获取请求路径
        String requestURI = request.getRequestURI();
        String method = request.getMethod();

        log.info("拦截器收到请求: {} {}", method, requestURI);

        //2.判断是否是登录请求，如果路径中包含login，则放行
        if(requestURI.contains("login")){
            log.info("登录请求，放行: {}", requestURI);
            return true;
        }

        //3.获取token - 支持两种方式
        String token = getTokenFromRequest(request);
        log.info("提取到的token: {}", token);

        //4.判断token是否存在
        if(token == null || token.isEmpty()){
            log.info("令牌为空，响应401 - 请求路径: {}", requestURI);
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write("{\"code\":401,\"message\":\"未授权，请先登录\"}");
            return false;
        }

        //5.检查token是否在黑名单中
        if (tokenBlacklist.isBlacklisted(token)) {
            log.info("令牌已失效（项目重启），响应401");
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write("{\"code\":401,\"message\":\"登录状态已过期，请重新登录\"}");
            return false;
        }

        //6.校验令牌有效性
        try {
            Claims claims = JwtUtils.parseToken(token);
            log.info("令牌解析成功 - 用户ID: {}, 用户名: {}",
                    claims.get("id"), claims.get("username"));

            // 将用户信息存入请求属性，供后续使用
            request.setAttribute("userId", claims.get("id"));
            request.setAttribute("username", claims.get("username"));

        } catch (Exception e) {
            log.info("令牌非法，响应401 - 错误: {}", e.getMessage());
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write("{\"code\":401,\"message\":\"令牌无效或已过期\"}");
            return false;
        }

        //7.校验成功，放行
        log.info("令牌合法，放行: {}", requestURI);
        return true;
    }

    /**
     * 从请求中提取token，支持两种方式：
     * 1. Authorization: Bearer {token}
     * 2. token: {token}
     */
    private String getTokenFromRequest(HttpServletRequest request) {
        // 方式1：检查Authorization头 (Bearer token)
        String authHeader = request.getHeader("Authorization");
        if (authHeader != null && !authHeader.isEmpty()) {
            log.info("Authorization头内容: {}", authHeader);
            if (authHeader.startsWith("Bearer ")) {
                String token = authHeader.substring(7);
                log.info("从Bearer提取token: {}", token);
                return token;
            } else {
                // 如果没有Bearer前缀，直接返回整个Authorization头
                log.info("直接使用Authorization头作为token: {}", authHeader);
                return authHeader;
            }
        }

        // 方式2：检查token头
        String tokenHeader = request.getHeader("token");
        if (tokenHeader != null && !tokenHeader.isEmpty()) {
            log.info("token头内容: {}", tokenHeader);
            return tokenHeader;
        }

        // 方式3：检查请求参数中的token（可选）
        String tokenParam = request.getParameter("token");
        if (tokenParam != null && !tokenParam.isEmpty()) {
            log.info("参数中的token: {}", tokenParam);
            return tokenParam;
        }

        log.info("未找到有效的token");
        return null;
    }
}